﻿#include <vtkAutoInit.h>

#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkCubeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

#include <vtkPointPicker.h>
//this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()
#include <vtkRendererCollection.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkObjectFactory.h>  //vtkStandardNewMacro();
#include <vtkProperty.h>

#include <vtkAxesActor.h>
#include <vtkCamera.h>
#include <vtkClipPolyData.h>
#include <vtkCutter.h>
#include <vtkInteractorStyleImage.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkPlane.h>
#include <vtkWorldPointPicker.h>

/**
 * 通过一个平面去验证相机和点的位置
 */

//VTK_MODULE_INIT(vtkRenderingOpenGL)
//VTK_MODULE_INIT(vtkRenderingFreeType)
//VTK_MODULE_INIT(vtkInteractionStyle)


static vtkSmartPointer<vtkRenderer> sRender;
/**************************************************************************************************/
class PointPickerInteractorStyle : public vtkInteractorStyleImage
{
public:
    static PointPickerInteractorStyle* New();
    vtkTypeMacro(PointPickerInteractorStyle, vtkInteractorStyleTrackballCamera);

    virtual void OnLeftButtonDown()
    {
        std::cout << "-------------------" << std::endl;
        pickPoint();
        std::cout << "-------" << std::endl;
        showPoint();
        vtkInteractorStyleImage::OnLeftButtonDown();
    }

    void pickPoint()
    {
        //打印鼠标左键像素位置
        std::cout << "Picking pixel: " << this->Interactor->GetEventPosition()[0]
            << " " << this->Interactor->GetEventPosition()[1] << std::endl;
        //注册拾取点函数
        this->Interactor->GetPicker()->Pick(
            this->Interactor->GetEventPosition()[0],
            this->Interactor->GetEventPosition()[1], 0,  // always zero.
                sRender
//            this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()
            );
        //打印拾取点空间位置
        double picked[3];
        this->Interactor->GetPicker()->GetPickPosition(picked);
        std::cout << "Picked value: " << picked[0] << " " << picked[1] << " " << picked[2] << std::endl;
        //对拾取点进行标记
        vtkSmartPointer<vtkSphereSource> sphereSource =
            vtkSmartPointer<vtkSphereSource>::New();
        sphereSource->Update();

        vtkSmartPointer<vtkPolyDataMapper> mapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
        mapper->SetInputConnection(sphereSource->GetOutputPort());

        vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
        actor->SetMapper(mapper);
        actor->SetPosition(picked);
        actor->SetScale(0.5);
        actor->GetProperty()->SetColor(0.0, 1.0, 0.0);
        sRender->AddActor(actor);
        // this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(actor);
    }

    void showPoint()
    {
        vtkRenderWindowInteractor *interactor = this->GetInteractor();
//        vtkRenderer               *render     = this->GetCurrentRenderer();
        vtkSmartPointer<vtkRenderer> render   = sRender;


        //获得 event 的 world 坐标
        int displayPosition[3];
        interactor->GetEventPosition(displayPosition);
        displayPosition[2] = 0;

        //打印鼠标左键像素位置
        std::cout << "displayPosition: " << displayPosition[0]
            << "," << displayPosition[1] << "," << displayPosition[2] << std::endl;

        // 转成空间点
        render->SetDisplayPoint((double)displayPosition[0], (double)displayPosition[1],
                (double)displayPosition[2]);
        render->DisplayToWorld();
        double worldPoint[4];
        render->GetWorldPoint(worldPoint);
        std::cout << "worldPoint: " << worldPoint[0] << "," << worldPoint[1] << "," << worldPoint[2]
                   << "," << worldPoint[3] << std::endl;

        //获得 last event的 world 坐标
        int lastDisplayPosition[3];
        interactor->GetLastEventPosition(lastDisplayPosition);
        std::cout << "lastDisplayPosition: " << lastDisplayPosition[0] << "," << lastDisplayPosition[1] << "," << lastDisplayPosition[2]
                   << std::endl;


        render->SetDisplayPoint((double)lastDisplayPosition[0], (double)lastDisplayPosition[1], (double)lastDisplayPosition[2]);
        render->DisplayToWorld();

        double  lastEventWorldPoint[4];
        render->GetWorldPoint(lastEventWorldPoint);

        std::cout << "lastEventWorldPoint: " << lastEventWorldPoint[0] << "," << lastEventWorldPoint[1] << "," << lastEventWorldPoint[2]
                   << std::endl;

        // camera
        vtkCamera *camera           = render->GetActiveCamera();
        double    *cameraPosition   = camera->GetPosition();
        double    *cameraFocalPoint = camera->GetFocalPoint();
        double    *cameraViewUp     = camera->GetViewUp();

        cameraFocalPoint[3] = 1.0;
        render->SetWorldPoint(cameraFocalPoint);
        render->WorldToDisplay();
        double *cameraDisplayP = render->GetDisplayPoint();

        std::cout << "cameraPosition: " << cameraPosition[0] << "," << cameraPosition[1] << "," << cameraPosition[2]
                   << std::endl;
        std::cout << "cameraFocalPoint: " << cameraFocalPoint[0] << "," << cameraFocalPoint[1] << "," << cameraFocalPoint[2];
        std::cout << " display: " << cameraDisplayP[0] << "," << cameraDisplayP[1] << "," << cameraDisplayP[2]
                   << std::endl;
        std::cout << "cameraViewUp: " << cameraViewUp[0] << "," << cameraViewUp[1] << "," << cameraViewUp[2]
                   << std::endl;

        render->SetDisplayPoint((double)displayPosition[0], (double)displayPosition[1],
                (double)cameraDisplayP[2]);
        render->DisplayToWorld();
        render->WorldToDisplay();
        render->GetWorldPoint(worldPoint);
        std::cout << "worldPoint: " << worldPoint[0] << "," << worldPoint[1] << "," << worldPoint[2]
                   << "," << worldPoint[3] << std::endl;
    }
};
/**************************************************************************************************/

vtkStandardNewMacro(PointPickerInteractorStyle);

int main()
{
//    vtkSmartPointer<vtkSphereSource> sphereSource =
//        vtkSmartPointer<vtkSphereSource>::New();
//    sphereSource->SetCenter(0.0, 0.0, 0.0);
//    sphereSource->SetRadius(2.0);
//    sphereSource->Update();


    // create the a cube
    vtkSmartPointer<vtkCubeSource> cube =
      vtkSmartPointer<vtkCubeSource>::New();
    cube->SetXLength(12);
    cube->SetYLength(8);
    cube->SetZLength(8);
    cube->SetCenter(0, 0, 0);
    cube->Update();

    vtkSmartPointer<vtkPlane> plane =
        vtkSmartPointer<vtkPlane>::New();
    plane->SetOrigin(0, 0, 2);
    plane->SetNormal(0, 0, 1);

//    vtkSmartPointer<vtkClipPolyData> clipPolyData =
//        vtkSmartPointer<vtkClipPolyData>::New();
//    clipPolyData->SetInputConnection(cube->GetOutputPort());
//    clipPolyData->SetClipFunction(plane);
//    clipPolyData->GenerateClippedOutputOn();
//    clipPolyData->Update();

    vtkSmartPointer<vtkCutter> cut = vtkSmartPointer<vtkCutter>::New();
    cut->SetInputData(cube->GetOutput());
    cut->SetCutFunction(plane);
    cut->GenerateCutScalarsOn();
    cut->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(cut->GetOutputPort());
//    mapper->SetInputConnection(clipPolyData->GetOutputPort());
    vtkSmartPointer<vtkActor> actor =
        vtkSmartPointer<vtkActor>::New();
    actor->GetProperty()->SetColor(0.5,0,0);
    actor->GetProperty()->SetOpacity(0.3);
    actor->SetMapper(mapper);

    // 加入原点
    vtkSmartPointer<vtkSphereSource> sphereSource =
        vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapperC =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperC->SetInputConnection(sphereSource->GetOutputPort());

    vtkSmartPointer<vtkActor> actorC = vtkSmartPointer<vtkActor>::New();
    actorC->SetMapper(mapperC);
    actorC->SetPosition(0, 0, 0);
    actorC->SetScale(0.5);
    actorC->GetProperty()->SetColor(0.0, 0.0, 1.0);


    vtkSmartPointer<vtkRenderer> renderer =
        vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(actorC);
    renderer->AddActor(actor);
    renderer->SetBackground(1, 1, 1);
    renderer->SetViewport(0, 0, 1, 1);

    vtkSmartPointer<vtkRenderWindow> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
//    renderWindow->Render();
    renderWindow->SetWindowName("PointPicker");
    renderWindow->AddRenderer(renderer);

//    vtkSmartPointer<vtkPointPicker> pointPicker =
//        vtkSmartPointer<vtkPointPicker>::New();
    vtkSmartPointer<vtkWorldPointPicker> pointPicker =
        vtkSmartPointer<vtkWorldPointPicker>::New();
//    pointPicker->DebugOff();

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetPicker(pointPicker);
    renderWindowInteractor->SetRenderWindow(renderWindow);

    sRender = renderer;
    vtkSmartPointer<PointPickerInteractorStyle> style =
        vtkSmartPointer<PointPickerInteractorStyle>::New();
    renderWindowInteractor->SetInteractorStyle(style);
    /////////////////////////////////////////////////////////
    vtkSmartPointer<vtkAxesActor>  Axes = vtkSmartPointer<vtkAxesActor>::New();
    vtkSmartPointer<vtkOrientationMarkerWidget>  widget =
        vtkSmartPointer<vtkOrientationMarkerWidget>::New();
    widget->SetInteractor(renderWindowInteractor);
    widget->SetOrientationMarker(Axes);
    widget->SetOutlineColor(1, 1, 1);
    widget->SetViewport(0, 0, 0.2, 0.2);
    widget->SetEnabled(1);
    widget->InteractiveOn();
    ////////////////////////////////////////////////////////////
    vtkSmartPointer<vtkCamera> rCamera =
        vtkSmartPointer<vtkCamera>::New();
//    rCamera->SetViewUp (0, 1, 0);
//    rCamera->SetPosition (0, 0, 40);
//    rCamera->SetFocalPoint (0, 0, 2);
//    rCamera->ComputeViewPlaneNormal();
    //        rCamera->Azimuth(30.0);
    //        rCamera->Elevation(30.0);
//    renderer->SetActiveCamera(rCamera);
    renderer->ResetCamera();
    renderer->GetActiveCamera()->SetFocalPoint(0, 0, 2);
//    renderer->GetActiveCamera()->SetPosition(0,0,40);
    renderer->GetActiveCamera()->SetViewUp(0, 1, 0);
//    renderer->GetActiveCamera()->ComputeViewPlaneNormal();


    renderWindow->Render();
    renderWindowInteractor->Start();

    return 0;
}
